from os.path import split, isfile, samefile, exists
from time import sleep

import chardet
from PyQt5.QtWidgets import QMainWindow, QAction, QTextEdit, QFileDialog, QMessageBox, QDesktopWidget, \
    QComboBox, QWidget, QHBoxLayout, QLabel, QStatusBar, QApplication
from PyQt5.QtGui import QIcon, QColor, QFont, QPixmap, QDesktopServices
from PyQt5.QtCore import Qt, QUrl, QSize, pyqtSignal, QThread

from config.ConfigReader import ConfigReader
from converter.TextConverter import TextConverter as Tc


class MyTextEdit(QMainWindow):
    _version = "v0.1.1"
    def __init__(self, exePath, log):
        super().__init__()

        self._log = log
        self._exe = exePath
        path, _ = split(exePath)
        self.config_path = path + r"\config\config.ini"
        self.config_reader = ConfigReader(self.config_path)
        self._setImg(path)
        try:
            self.FixedSize = int(self.config_reader.get_settings("FixedSize"))
            self.RecentFile = eval(self.config_reader.get_files("RecentFile"))
        except Exception:
            self.FixedSize = 1
            self.RecentFile = []
            self._log.exception(Exception("配置文件异常，部分属性已使用默认值！"))
        self.currentFilePath = ""
        self.msg = ""
        self.error = self.first = 1

        # 设置窗口标题和图标
        self.setWindowTitle("MarDisTextConverter——源文本转换编辑器          ♥~\\(≧v≦*~\\)0Oo。")
        icon = QIcon(self._Icon)
        self.setWindowIcon(icon)
        self.windowIcon().addFile("icon.png", QSize(48, 48))

        # 设置窗口大小和位置
        self.setGeometry(300, 200, 820, 760)
        if self.FixedSize:
            self.setFixedSize(820, 760)
        # 透明度
        self.setWindowOpacity(0.95)
        self.center()
        # 添加工具栏和按钮
        toolbar = self.addToolBar("主工具栏")

        # 取消默认主工具栏选项
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(lambda: None)

        # 设置撤回组件
        undoAction = QAction(self)
        undoAction.setShortcut('Ctrl+Z')
        self.addAction(undoAction)

        # 添加菜单栏
        self.menubar = self.menuBar()

        file_menu = self.menubar.addMenu("文件")
        self._addQAcion(file_menu, "新建文件", "", "快捷键：Ctrl+N", "Ctrl+N" ,self.createFile)
        self._addQAcion(file_menu, "打开", "", "快捷键：Ctrl+O", "Ctrl+O" ,self.openFile)
        self._addQAcion(file_menu, "保存", key="Ctrl+S", slot=self.saveCurrentFile)
        self._addQAcion(file_menu, "文件另存为...", key="Ctrl+Shift+S", slot= lambda : self.saveFile(1))
        self.recent_files_menu = file_menu.addMenu('最近打开的文件')
        if self.RecentFile:
            self.updateRecent()

        edit_menu = self.menubar.addMenu("编辑")
        self.textEdit = QTextEdit()
        self.textEdit.textChanged.connect(self.calculate_char_count)
        self._addQAcion(edit_menu, "撤回", key="Ctrl+Z", slot=self.textEdit.undo)
        self._addQAcion(edit_menu, "复制", key="Ctrl+C", slot=self.textEdit.copy)
        self._addQAcion(edit_menu, "剪切", key="Ctrl+X", slot=self.textEdit.cut)
        self._addQAcion(edit_menu, "黏贴", key="Ctrl+V", slot=self.textEdit.paste)
        self._addQAcion(edit_menu, "清空文本框", key="Ctrl+L", slot=self._clear)

        self.copypath = QAction("拷贝文件路径", self)
        self.copypath.triggered.connect(self.copyPath)
        self.copypath.setEnabled(False)
        edit_menu.addAction(self.copypath)

        setup_menu = self.menubar.addMenu("设置")
        self._addQAcion(setup_menu, "打开配置文件", key="Ctrl+Alt+S", slot=lambda: self.openFile(self.config_path))
        self._addQAcion(setup_menu, "恢复默认设置", slot=self._restoreDefaults)

        self.widget = QWidget(self)
        layout = QHBoxLayout(self.widget)
        self.menuRLable = QLabel(" " * 120)
        self.menuRLable.setAlignment(Qt.AlignRight)
        layout.addWidget(self.menuRLable)
        layout.setContentsMargins(5, 3, 5, 0)
        self.widget.setLayout(layout)

        self.updateT = self.WorkerThread()
        self.updateT.update_signal.connect(self._outputText)
        self.updateT.start()

        # 将包含文本标签的布局添加到菜单栏的角
        self.menubar.setCornerWidget(self.widget)

        # 工具栏各按钮添加、描述并设置快捷键
        self.convertComboBox = QComboBox(self)
        self.convertComboBox.addItem("Markdown 转 Discuz")
        self.convertComboBox.addItem("Discuz 转 Markdown")
        self.convertComboBox.setCurrentIndex(0)
        self._addQAcion(key="Ctrl+Shift+D", slot=self.MarToDis)
        self._addQAcion(key="Ctrl+Shift+M", slot=self.DisToMar)
        self.convertComboBox.setToolTip("转换格式")
        toolbar.addWidget(self.convertComboBox)
        self._addQAcion(toolbar, "打开", self._Open, "打开文件（Ctrl+O）", "Ctrl+O", self.openFile)
        self._addQAcion(toolbar,"保存", self._Save, "保存文件（快捷键：Ctrl+S）", "",
                        self.saveCurrentFile)
        self._addQAcion(toolbar,"转换", self._Convert, "转换格式（快捷键：Ctrl+T）", "Ctrl+T",
                        self.convert)
        self._addQAcion(toolbar,"帮助", self._Help, "打开帮助页面（快捷键：Ctrl+H）", "Ctrl+H",
                        self.showHelp)
        self._addQAcion(toolbar,"关于", self._About, "更多信息", slot=self.showAbout)
        self._addQAcion(toolbar,"最小化", self._Minimize, "最小化窗口（快捷键：Ctrl+M）", "Ctrl+M",
                        self.minimizeWindow)
        self.maxButton = self._addQAcion(toolbar,"最大化", self._Maximize, "最大/恢复化窗口（快捷键：Ctrl+D）", "Ctrl+D",
                        self.showMaximizedOrRestore)
        self._addQAcion(toolbar,"退出程序", self._Exit, "退出应用程序（Ctrl+Q）", "Ctrl+Q",
                        self.close)

        if self.FixedSize:
            self.maxButton.setEnabled(False)

        # 设置工具栏按钮占满整个工具栏
        toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        toolbar.setStyleSheet(self.config_reader.get_style("QButton"))
        toolbar.setStyleSheet(self.config_reader.get_style("QToolBar"))

        # 设置窗口颜色主题
        palette = self.palette()
        palette.setColor(palette.Window, QColor(130, 183, 219))
        self.setPalette(palette)

        # 设置文本编辑框
        self.textEdit.setAcceptRichText(False)
        # 调整字体大小
        self.textEdit.setFont(QFont("Microsoft YaHei", 12))

        self.setCentralWidget(self.textEdit)
        # 设置编辑器背景颜色
        self.textEdit.setStyleSheet(self.config_reader.get_style("textEditBg"))

        # 创建一个状态栏
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.count_label = QLabel(f'共计：0 行  字符个数为：0', self.status_bar)
        self.count_label.setAlignment(Qt.AlignRight)
        self.status_bar.addWidget(self.count_label)
        self.status_bar.addPermanentWidget(self.count_label)
        self.file_label = QLabel("<b>当前暂未打开文件...</b>")
        self.file_label.setAlignment(Qt.AlignCenter)
        self.status_bar.addWidget(self.file_label)

    class WorkerThread(QThread):
        update_signal = pyqtSignal(str)  # 自定义信号

        def __init__(self):
            super().__init__()
            self.text = ""
            self.idx = 1

        def run(self):
            while True:
                if self.idx < len(self.text) + 1:
                    self.update_signal.emit(self.text[:self.idx])
                    self.idx += 1
                sleep(0.04)

        def setText(self, text):
            self.idx = 1
            self.text = text

    # 读取配置文件获取图片路径
    def _setImg(self, path):
        sections = self.config_reader.config._sections["icons"]
        for k in sections:
            setattr(MyTextEdit, "_" + k[:1].upper() + k[1:], path + sections[k])

    def _clear(self):
        self.textEdit.selectAll()
        self.textEdit.textCursor().removeSelectedText()
    def MarToDis(self):
        self.convertComboBox.setCurrentIndex(0)
        self.convert()

    def DisToMar(self):
        self.convertComboBox.setCurrentIndex(1)
        self.convert()

    # 创建新文件
    def createFile(self):
        msgBox = QMessageBox(self)
        icon = QIcon(self._New)
        msgBox.setIconPixmap(icon.pixmap(48, 48))
        msgBox.setWindowIcon(QIcon(self._Icon))
        msgBox.setWindowTitle("创建新文件")
        msgBox.setText("在新窗口中创建并打开新文件，还是本窗口？")
        msgBox.addButton("新窗口", QMessageBox.YesRole)
        msgBox.addButton("本窗口", QMessageBox.NoRole).setFocus()
        msgBox.addButton("取消", QMessageBox.RejectRole)
        isNew = msgBox.exec_()
        if isNew == 0:
            self.updateT.setText("Biu~</b> (*/ω \*)嘿嘿，又冒出一个我~")
            QDesktopServices.openUrl(QUrl.fromLocalFile(self._exe))
        elif isNew == 1:
            self.textEdit.selectAll()
            self.textEdit.textCursor().removeSelectedText()
            self.currentFilePath = ""
            self.file_label.setText(f" <b>新建文件</b>，暂未保存... ")
            self.updateT.setText("ψ(._.  )、 嘿咻~</b> 我帮你清空了文本框的文字啦~ ")
        else:
            self.updateT.setText("(*＾-＾*)</b> 你取消了新文件的创建哦~ ")

    # 统计文本数据信息
    def calculate_char_count(self):
        text = self.textEdit.toPlainText()
        char_count = len(text)
        doc = self.textEdit.document()
        line_count = doc.lineCount()
        self.count_label.setText(f'共计： <b>{line_count}</b> 行  字符个数为：<b>{char_count}</b>')

    # 更新左下角当前打开的文件
    def update_file_label(self, fileName):
        self.file_label.setText(f"当前文件：<b>{fileName}</b>")
    # 恢复默认设置
    def _restoreDefaults(self):
        reply = QMessageBox.question(
            self, '是否恢复默认配置？...(*°▽°*)~！',
            '此操作会将配置恢复为<span style="color:red; font-weight:bold;">默认配置</span>！',
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

        if reply == QMessageBox.Yes:
            self.config_reader.restore = 1
            self.config_reader.save_Config(Tc._ConfigureBackup)
            Tc._loadConfig(True)
            self.openFile(self.config_path, True)
            self.config_reader.restore = 0
        else:
            self.updateT.setText("(*/ω＼*)</b>￥@!呼....好可怕，差点...失忆!")

    # 移动窗口屏幕中央
    def center(self):
        screen = QDesktopWidget().screenGeometry()
        x = (screen.width() - self.width()) // 2
        y = (screen.height() - self.height()) // 2
        self.move(x, y)


    # 添加工具栏按键
    def _addQAcion(self, module=None, name="", img_path="", tip="", key=None, slot=None):
        if img_path:
            action = QAction(QIcon(img_path), name, self)
        else:
            action = QAction(name, self)
        action.setToolTip(tip) if tip else None
        action.setShortcut(key) if key else None
        action.triggered.connect(slot)
        if module != None:
            module.addAction(action)
        else:
            self.addAction(action)
        return action

    # 拷贝文件路径
    def copyPath(self):
        QApplication.clipboard().setText(self.currentFilePath)

    # 添加到最近文件列表
    def addRecent(self, path):
        if path in self.RecentFile:
            self.RecentFile.remove(path)
        elif len(self.RecentFile) == 5:
            self.RecentFile.pop()
        self.RecentFile.insert(0, path)
        self.updateRecent()

    # 更新最近文件列表
    def updateRecent(self):
        self.recent_files_menu.clear()
        for i in range(len(self.RecentFile)):
            file_action = self.recent_files_menu.addAction(f"{i + 1}. {split(self.RecentFile[i])[1]}")
            file_action.triggered.connect(self.open_recent_file)
        self.config_reader.update_recentFile(self.RecentFile)

    # 打开最近文件
    def open_recent_file(self):
        file = self.sender().text()
        idx, fileName = file.split(". ", 1)
        filePath = self.RecentFile[int(idx) - 1]
        self.openFile(filePath)

    # 打开文件
    def openFile(self, filePath="", confmsg=False):
        temp = False
        flag = self.msg
        try:
            if not filePath:
                filePath, _ = QFileDialog.getOpenFileName(self, "选择文件", "",
                                                          "*.txt, *.md, ... (*.*);;文本文档 (*.txt);;Markdown 文档 (*.md)")
            temp = True
            if filePath != "" and not isfile(filePath):
                self.msg = f"抱歉嗷~</b> 我似乎找不到文件呢 /(￣x￣)/~~？"
            elif filePath:
                self.currentFilePath = filePath
                with open(filePath, encoding=Tc._getFileEncoding(filePath)) as f:
                    text = f.read().replace("\u200b", "\t")
                    self.textEdit.setPlainText(text)
                self.error, fileName = 1, split(filePath)[1]

                self.msg = f"[{fileName}]</b> 已经打开！<b>o(*￣v￣*)o</b>" if not confmsg else f"<b>o(*￣w￣*)o</b> 配置已还原~！"

                self.update_file_label(fileName)
                self.updateRecent()
                # 添加入最近打开的文件菜单项
                self.addRecent(filePath)
                self.copypath.setEnabled(True)
            elif not self.currentFilePath:
                self.msg = f"咦 (⊙o⊙)？</b> 似乎没有选择打开文件嗷！"
        except Exception as e:
            if temp and filePath:
                self.error, fileName = 0, split(filePath)[1]
                self.msg = f"[{fileName}]</b> 打开失败！<b>/(ㄒoㄒ)/~~</b> 可能<b>不支持</b>此类文件嗷！"
            else:
                self.msg = f"程序异常，请到程序根目录下的 debug.log 中查看异常信息</b> "
                raise e
        if self.msg != flag:
            self.updateT.setText(self.msg)

    # 信号槽函数，更新菜单栏右侧 Label
    def _outputText(self, text):
        self.menuRLable.setText("<b>" + text)

    # 覆盖当前打开文件
    def saveCurrentFile(self):
        if isfile(self.currentFilePath) and self.error:
            path, fileName = split(self.currentFilePath)
            try:
                _isOrNo = QMessageBox.question(
                    self, '保存文件 (~^_^)~',
                    f'是否<span style="color:red; font-weight:bold;">覆盖<b>{fileName}</b>文件</span>（建议<b>备份</b>后保存）进行保存？',
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if _isOrNo == QMessageBox.Yes:
                    if not self.saveConfig(self.currentFilePath):
                        with open(self.currentFilePath, "w", encoding=Tc._getFileEncoding(self.currentFilePath)) as f:
                            f.write(self.textEdit.toPlainText())
                    else:
                        Tc._loadConfig(True)
                    self.msg = f"[{fileName}]</b> 文件保存成功！<b>~(*^_^*)~</b>"
                else:
                    self.msg = f"取消保存，建议备份文件后保存</b> <b>(~^o^~)</b>"

            except Exception as e:
                self.msg = f"[{fileName}]</b> 文件保存失败！<b>~(*ㄒoㄒ*)~</b> 异常原因：<span  style='color: red; font-weight:bold;'>{str(e)}</span>"
                self._log.exception(e)
            self.updateT.setText(self.msg)
        else:
            self.saveFile()

    # 保存文件
    def saveFile(self, saveAs=0):
        flag = 0
        try:
            path, fileName = "", "FishC.txt"
            if self.currentFilePath:
                path, filePath = split(self.currentFilePath)
            filePath, _ = QFileDialog.getSaveFileName(self, "保存文件", fileName,
                                                      "文本文档 (*.txt);;Markdown 文档 (*.md)")
            if filePath:
                if saveAs or not self.saveConfig(filePath):
                    if saveAs or not exists(filePath):
                        encoding = "utf-8"
                    else:
                        encoding = Tc._getFileEncoding(filePath)
                    with open(filePath, "w", encoding= encoding)  as f:
                        f.write(self.textEdit.toPlainText())
                _, fileName = split(filePath)
                self.msg = f"[{fileName}]</b> 文件保存成功！<b>~(=￣ω￣=)~</b>"
                if saveAs:
                    self.currentFilePath = filePath
                self.update_file_label(fileName)
                flag = 1
                self.addRecent(filePath)
                self.copypath.setEnabled(True)
        except Exception as e:
            if filePath:
                _, fileName = split(filePath)
                self.msg = f"[{fileName}]</b> 文件保存失败！<b>~(*ㄒoㄒ*)~</b> 异常原因：<span  style='color: red; font-weight:bold;'>{str(e)}</span>"
            else:
                self.msg = f"~(*ㄒoㄒ*)~ </b> 文件保存失败！异常原因：<span  style='color: red; font-weight:bold;'>{str(e)}</span>"
            self._log.exception(e)
            flag = 1
        if flag:
            self.updateT.setText(self.msg)

    # 保存配置
    def saveConfig(self, path):
        if exists(path) and samefile(self.config_path, path):
            self.config_reader.save_Config(ConfigReader(self.textEdit.toPlainText(), True).config._sections)
            self.msg = "[config.ini}]</b> 文件保存成功！<b>~(=￣ω￣=)~</b>"
            self.update_file_label("config.ini")
            self.addRecent(path)
            self.copypath.setEnabled(True)
            return True
        return False

    # 转换
    def convert(self):
        try:
            if not self.textEdit.toPlainText().strip():
                raise Exception("文本框中无内容，转换个空气...给我系内！")
            elif self.currentFilePath and samefile(self.currentFilePath, self.config_path):
                raise Exception("(ˉ▽ˉ；)... 这是我配置文件，<b>无需</b>转换嗷！")
            currentIndex = self.convertComboBox.currentIndex()
            if currentIndex == 0:
                # 进行 Markdown 转 Discuz 操作
                text = Tc.markdownToDiscuz(self.textEdit.toPlainText())
                self.textEdit.setPlainText(text)
                self.msg = f"Markdown → Discuz</b> 文件转换成功！<b>(～￣▽￣)～</b>"
            elif currentIndex == 1:
                # 进行 Discuz 转 Markdown 操作
                text = Tc.discuzToMarkdown(self.textEdit.toPlainText())
                self.textEdit.setPlainText(text)
                self.msg = f"Discuz → Markdown</b> 文件转换成功！<b>～(￣▽￣～)</b>"

        except Exception as e:
            self.msg = f"可恶</b>，失败了！<b>~(/T^T\)~</b>异常原因：<span style='color=red; font-weight:bold;'>{str(e)}</span>"
            self._log.exception(e)
        self.updateT.setText(self.msg)

    # 显示帮助
    def showHelp(self):
        reply = QMessageBox.question(
            self, '是否跳转？^3^',
            '是否<span style="color:red; font-weight:bold;">跳转</span>到帮助页面？',
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.updateT.setText(f"mua~</b>偷偷看帮助被我逮着啦！<b>(*￣3￣)~</b>")
            url = QUrl("https://fishc.com.cn/thread-227318-1-1.html")
            QDesktopServices.openUrl(url)
        else:
            self.updateT.setText(f"(o/>^&lt;\o)</b> 难道......你对我不感兴趣吗？")

    # 最小化窗口
    def minimizeWindow(self):
        self.showMinimized()

    # 最大化或还原窗口
    def showMaximizedOrRestore(self):
        if self.isMaximized():
            self.showNormal()
            self.updateT.setText("嗷呜！~(●'◡'●~)</b> 我变回来啦!")
            self.maxButton.setIcon(QIcon(self._Maximize))
            self.maxButton.setText("最大化")
            self.maxButton.setToolTip("最大化窗口（快捷键：Ctrl+D）")
        else:
            self.showMaximized()
            self.updateT.setText("哇嗷！(~●'◡'●)~</b> 我变大啦!")
            self.maxButton.setIcon(QIcon(self._Restore))
            self.maxButton.setText("恢复窗口")
            self.maxButton.setToolTip("恢复窗口大小（快捷键：Ctrl+D）")

    # 窗口栏点击最大化
    def resizeEvent(self, event):
        if self.isMaximized():
            self.updateT.setText("嗷呜！~(●'◡'●~)</b> 我变回来啦!")
        else:
            if not self.first:
                self.updateT.setText("哇嗷！(~●'◡'●)~</b> 我变大啦!")
        self.first = 0
        return super().resizeEvent(event)

    # 窗口栏点击关闭
    def closeEvent(self, event):
        self.config_reader.save_Config()
        reply = QMessageBox.question(self, '确认', '确定退出程序？', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

        self.updateT.setText("(/≧▽≦)/</b> 我就知道你不会离开我 ❤~")

    # 显示关于
    def showAbout(self):
        # 弹出作者信息框
        aboutBox = QMessageBox(self)
        aboutBox.setWindowTitle("关于作者")
        aboutBox.setIconPixmap(QPixmap("UangSC"))
        aboutBox.setStyleSheet("background-color:#CBDCE9;")
        aboutBox.setText(
            f"<br><div style='text-align:center; font-size:12pt; font-family:STKaiti; font-weight:bold;'>版本号：{self._version}<hr>作者：Twilight6（UangSC）<br>QQ：327981933<br>码云：<a href='https://gitee.com/UangSC/TextConverter'>啥都木有</a><br>论坛：<a href='https://fishc.com.cn/space-uid-854664.html'>鱼C论坛</a><br>Email：UangSC@foxmail.com</div>")
        aboutBox.setTextFormat(Qt.RichText)
        desktop = QDesktopWidget()
        screenWidth = desktop.screenGeometry().width()
        screenHeight = desktop.screenGeometry().height()
        centerX = int(screenWidth / 2)
        centerY = int(screenHeight / 2)
        x = aboutBox.sizeHint().width()
        y = aboutBox.sizeHint().height()
        aboutBox.move(centerX - int((aboutBox.width() + x) / 2), centerY - int((aboutBox.height() + y) / 2))
        aboutBox.exec_()
        self.updateT.setText("(*/ω＼*)</b> 主动就会有结果 ❤~")
